﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SG.Domain;

namespace SG.Logic.Stock
{
   
    
public class ExponencialEstacionalidad : Exponencial {


    public override void ActualizarPeriodo(Periodo anterior, Periodo nuevo)
    {
        Articulo art = nuevo.Articulo;
        int maxEstacion = anterior.Articulo.Indice.Max(f => f.NumeroEstacion);
        int numeroEstacionAObtener = (anterior.NumeroPeriodo + 1 == maxEstacion) ? 1 : anterior.NumeroPeriodo + 1;
        


        Indice indice = anterior.Articulo.Indice.Single(f => f.NumeroEstacion ==numeroEstacionAObtener);
        Indice indiceAnt = anterior.Articulo.Indice.Single(f => f.NumeroEstacion == (numeroEstacionAObtener==1?maxEstacion:numeroEstacionAObtener-1));
        
        double indEstAnt;
        /*int numeroPeriodoUltimaEst;
        
        if (indice != null && indice.fueUsuado==0) {
          
         */
            indEstAnt = indice.Valor;
            indice.fueUsuado=1;
        /*} else {
            numeroPeriodoUltimaEst = nuevo.NumeroPeriodo- art.CantEstaciones;

            Criterio criPeriodo = new Criterio();
            criPeriodo.setClase(typeof(Periodo) );
            criPeriodo.addCriterio("numeroPeriodo", numeroPeriodoUltimaEst, "=");
            criPeriodo.addCriterio("articulo", art, "=");
            Periodo per = Context.Periodo.FirstOrDefault();
            Criterio criIndice = new Criterio();
            criIndice.setClase(typeof(Indice));
            criIndice.addCriterio("numeroEstacion", per.NumeroEstacion, "=");
            criIndice.addCriterio("articulo", art, "=");
            indice = Context.Indice.FirstOrDefault();
            indEstAnt = indice.Valor;
        }*/

        _prom = CalcularPromedio(nuevo.Demanda, anterior.Promedio, indiceAnt.Valor, anterior.Articulo.Alpha);
        _indice = CalcularIndice(nuevo.Demanda, _prom, indiceAnt.Valor, art.Gamma);
        nuevo.Promedio=_prom;
        nuevo.Indice= _indice;
        nuevo.NumeroEstacion=indice.NumeroEstacion;
        indice.Valor=_indice;
        nuevo.Prediccion = nuevo.Promedio * indEstAnt;
        CalcularErrores(anterior, nuevo);

        if(nuevo.Id==0)
            Context.Periodo.AddObject(nuevo);
    }


    public override double GenerarPrediccion(Periodo perUltimo, int h)
    {
        Articulo art = perUltimo.Articulo;
        int maxEstacion = perUltimo.Articulo.Indice.Max(f => f.NumeroEstacion);
        int numeroEstacionAObtener = (perUltimo.NumeroPeriodo + 1 == maxEstacion) ? 1 : perUltimo.NumeroPeriodo + 1;

        //int numeroPeriodoAct = perUltimo.NumeroPeriodo + 1;
        //int numeroPeriodoAnt = numeroPeriodoAct - art.CantEstaciones;
        Indice indice = null;
        double indEstAnt;
        //int numeroEstacion;
        //int diferencia;
        DateTime fechaPerAct = CalcularFecha(perUltimo.Fecha, perUltimo.NumeroPeriodo + 1, art.CantDias);

        Console.WriteLine("estoy generando prediccion. antes fecha:" + fechaPerAct);
        indice = perUltimo.Articulo.Indice.Single(f=>f.NumeroEstacion==numeroEstacionAObtener) ;//ObtenerIndiceCorrespondiente(fechaPerAct, art);

        //if (indice != null && indice.fueUsuado==0 && (numeroPeriodoAct - perUltimo.NumeroPeriodo)<= art.CantEstaciones) {
            indEstAnt = indice.Valor;
        /*} else {
            if (numeroPeriodoAnt == perUltimo.NumeroPeriodo) {
                numeroEstacion = perUltimo.NumeroEstacion;
            } else if(numeroPeriodoAnt <= perUltimo.NumeroPeriodo) {
                diferencia =  numeroPeriodoAct - perUltimo.NumeroPeriodo;
                numeroEstacion = perUltimo.NumeroEstacion - (art.CantEstaciones-diferencia);
                if (numeroEstacion <= 0) {
                    numeroEstacion = perUltimo.NumeroEstacion + diferencia;
                }
            } else {
                diferencia = numeroPeriodoAct - perUltimo.NumeroPeriodo;
                int cociente = (int) (diferencia/art.CantEstaciones);
                Console.WriteLine("cociente: "+ cociente);
                int resto = diferencia - (art.CantEstaciones * cociente);
                numeroEstacion = perUltimo.NumeroEstacion + resto;
                if (numeroEstacion > art.CantEstaciones) {
                    numeroEstacion = perUltimo.NumeroEstacion - (art.CantEstaciones- resto);
                }
            }

            indice = Context.Indice.Where(f => f.IdArticulo == perUltimo.IdArticulo && f.NumeroEstacion == numeroEstacion).FirstOrDefault();
           
            indEstAnt = indice==null? 0:indice.Valor;
        }*/

        //Console.WriteLine("estoy generando prediccion. Indice: " + indice.NumeroEstacion);

        return (perUltimo.Promedio * indEstAnt);
    }


    public override double CalcularDesviacionEst(double mseAct)
    {
        return (Math.Sqrt(mseAct));
    }

    public double CalcularPromedio(double dr, double promAnt, double indEstAct, double alpha) {
        return (alpha * dr / indEstAct + (1.0 - alpha) * promAnt);
    }

    public double CalcularIndice(double demanda, double promedio, double indiceAnterior, double gamma) {
        return (gamma * demanda / promedio + (1.0 - gamma) * indiceAnterior);
    }

    private DateTime CalcularFecha(DateTime fec, int h, int cantDias) {
        DateTime fecha = new DateTime(fec.Year, fec.Month, fec.Day);
        
        fecha=fecha.AddDays(cantDias * h);

        return fecha;
    }

    private Indice ObtenerIndiceCorrespondiente(DateTime fecha, Articulo art)
    {
        int cantDiasEstacion = art.CantDias;
        List<Indice> indices = art.Indice.ToList();
        DateTime temp = new DateTime();
        DateTime inicio = new DateTime();
        DateTime fin = new DateTime();
         temp = new DateTime(fecha.Year, fecha.Month, fecha.Day);
     
        

        for (int i = 0; i < indices.Count; i++) {
            if (i == 0 ) {
                temp = new DateTime(indices[i].fechaInicio.Year, temp.Month, temp.Day);
            }

            inicio = new DateTime(indices[i].fechaInicio.Year, indices[i].fechaInicio.Month, indices[i].fechaInicio.Day);
            fin = new DateTime(indices[i].fechaInicio.Year, indices[i].fechaInicio.Month, indices[i].fechaInicio.Day);
            fin=fin.AddDays(cantDiasEstacion-1);
            

            if (temp.CompareTo(inicio) >=0 && temp.CompareTo(fin) <=0) {
                return indices[i];
            } else if (temp.CompareTo(inicio) < 0) {
                temp.AddYears(1);
                
                if (temp.CompareTo(inicio) >=0 && temp.CompareTo(fin) <=0) {
                    return indices[i];
                }
            }
        }

        return null;
    }

}
}
